package org.kwisatz.proxybot;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.httpclient.HttpClient;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.w3c.tidy.Tidy;

/**
 * A filter which ask for data over the Internet.
 * Common uses are !wikipedia and !google
 */
public abstract class HttpQueryFilter extends FilterAdapter
{
	private Pattern pattern;
	private String contCommand;
	protected HttpClient httpClient = new HttpClient();
	protected XPath xpath=XPathFactory.newInstance().newXPath();
	private int contCounter=0;
	
	protected HttpQueryFilter(String command)
	{
		pattern=Pattern.compile("^!"+command+" +(.+)$");
		contCommand = '!' +command+ '-';
	}
	
	protected abstract void handleQuery(String arguments, PrintWriter out);
	
	/**
	 * Handle the !next command. Overwrite it in subclasses.
	 * By default it does nothing, as this method is not relevant for most
	 * HttpQueryFilter commands.
	 * It's supposed to return instantly so you should have buffered
	 * everything in handleQuery.
	 * @param index the number of already called !cont commands
	 */
	protected void handleContinue(int index, PrintWriter out){}
	
	public final String handleClientLine(String line, Message message)
	{			
		if(message.getCommand().equals(Message.PRIVMSG))
		{
			if(handleNext(message))
				//does not display !cont command in the chan
				return null;
			handleQuery(message);
		}
		return line;
	}
	
	/** Handle the query (!wikipedia, !google etc ..) */
	private void handleQuery(final Message message)
	{
		Matcher m = pattern.matcher(message.getEndOfMsg());
		if(m.matches())
		{
			contCounter=0;
			final String arguments=m.group(1);
			new Thread()
			{
				public void run()
				{
					try
					{
						Thread.sleep(50);
						handleQuery(arguments, createOutput(message));
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}.start();
		}		
	}

	/** Create an output stream to send answers of the query to the client */
	PrintWriter createOutput(Message message)
	{
		final String chan=message.getCmdParam();
		final String prefix= ':' +context.getNickName()+
			"!proxybot@localhost PRIVMSG "+chan+" :";		
		return new PrintWriter(context.getServer())
		{
			public void println(String x)
			{
				context.getServer().println("PRIVMSG "+chan+" :"+x);
				context.getClient().println(prefix+x);
			}
		};	
	}
	
	/** Handle !cont command */
	private boolean handleNext(Message message)
	{
		boolean toReturn=message.getEndOfMsg().equals(contCommand);
		if(toReturn)
		{
			contCounter ++ ;
			handleContinue(contCounter, createOutput(message));
		}
		return toReturn;
	}

	protected static String getTextString(Node n)
	{
		if(n.getNodeType()==Node.TEXT_NODE)
			return n.getNodeValue();
		String s="";
		boolean isUL= "ul".equalsIgnoreCase(n.getNodeName());
		NodeList nl = n.getChildNodes();
		for(int i=0; i<nl.getLength(); i++)
		{
			if(i>0 && isUL)
				s+=", ";
			s+=getTextString(nl.item(i));			
		}
		return s;
	}
	
	protected static Document parseDOM(InputStream reader)
	{
		Tidy tidy=new Tidy();
		tidy.setQuiet(true);
		tidy.setShowWarnings(false);
		tidy.setIndentContent(true);
		return tidy.parseDOM(reader, null);
	}
	
	protected static Document parseDOM(InputStream reader, String encoding)
	{
		Tidy tidy=new Tidy();		
		tidy.setQuiet(true);
		tidy.setShowWarnings(false);
		tidy.setIndentContent(true);
		tidy.setInputEncoding(encoding);
		tidy.setShowErrors(0);
		return tidy.parseDOM(reader, null);
	}
	
	/**
	 * Return a slice of text
	 * @param index the id of the slice to return
	 * @param string the string to cut
	 * @param n the size of the slices
	 */
	protected static String slice(int index, String string, int n)
	{
		int startIndex = index*n;
		int endIndex = (index+1)*n;		
		int l=string.length();		

		String prefix;
		String suffix;

		if(endIndex>l)
		{
			endIndex=l;
			suffix="";
		}
		else
			suffix="...";

		if(startIndex>l)
			return "";
		
		if(startIndex>0)
			prefix="...";
		else
			prefix="";
		
		return prefix + string.substring(startIndex, endIndex).trim() + suffix;
	}
	
	/** Debug slice method */
	public static void main(String[] args) {
		String test="qdf sdfz iogub lkzer vlkj zpreitgrrzer  vkjskfjdkjfs erkjerizr v;k,cxvkjf";
		int i=0;
		String s=slice(i++, test, 10);
		while( s.length() !=0 )
		{
			System.out.println(s);
			s=slice(i++, test, 10);
		}
	}
}